/**
 * 发布订阅系统
 * @namespace pubsub
 */
/**
 * 创建一个发布订阅系统
 * @memberOf pubsub
 * @return {object} 独立的发布订阅系统
 */
function initPB() {

    var Observable = {
        /**
         * 发布消息
         *
         * @param  {string} eventName
         * @param  {object|string} data
         * @return {this}
         */
        publish: function(eventName, data) {
            this.$que.forEach(function(q) {
                if (q[eventName]) {
                    //队列在执行的时候，可能会遭遇到解绑自身绑定函数，导致后面相连的没有被执行
                    q[eventName].concat().forEach(function(fn) {
                        fn(data, eventName);
                    })
                }
            })
            return this;
        },
        /**
         * 解除订阅，可解除整个管道，或具体到一个具体函数
         * @param  {string} eventName
         * @param  {string=} fnName    可选的 function name
         * @return {this}
         */
        unbind: function(eventName, fnName) {
            var re = [];
            if (eventName === '$all') {

                for (var i = 0, channelName; channelName = this.$channel[i++];)
                    if (channelName in this.$jcQueue) {
                        re.push(this.$jcQueue[channelName])
                        delete this.$jcQueue[channelName]
                    }
                    //TODO: return what
                return re;
            }
            this.$que.forEach(function(q) {
                if (fnName) {
                    q[eventName].forEach(function(fn, index, arr) {
                        if (fn.fnName === fnName)
                            re.push(arr.splice(index, 1))
                    })
                } else {
                    re = q[eventName]
                    delete q[eventName]
                }
            })
            return re;
        },
        /**
         * 通过正则，获取匹配的eventName
         *
         * @param  {Object} reg
         * @return {Array}
         */
        eventNamesWithReg: function(reg) {
            var re = [];
            if (typeof reg === 'string')
                reg = new RegExp(reg)
            this.$que.forEach(function(queue) {
                for (var eventName in queue) {
                    if (reg.test(eventName))
                        re.push(eventName)
                }
            })
            return re
        },
        /**
         * 订阅事件，函数名称可不填,函数名称也可以用来归类
         * @param  {string }   eventName
         * @param  {string=}   fnName  option
         * @param  {function} fn
         * @return {this}
         */
        bind: function(eventName, fnName, fn) {
            // TODO 重复的剔除

            if (fn === undefined) {
                fn = fnName
            } else {
                fn.fnName = fnName
            }

            this.$que.forEach(function(que) {
                var eventArr = que[eventName];
                if (!eventArr)
                    eventArr = que[eventName] = [];
                eventArr.push(fn)
            })
            return this;
        }
    };

    /**
     * 进入channel，channel如果不存在，则创建
     * @param  {array|string} queues 传入数组或者"ab,v,d"字符串，当传参为 "$all"/["$all"]时，表示选择所有channel
     * @return {object}        返回Observable关于订阅的操作方法
     */
    function pb(queues) {
        var $que = [],
            jcQueue = pb.fn.$jcQueue;
        //var re = {};

        if (getType(queues) === 'string') {
            queues = queues.match(rword)
        }
        if (queues[0] === '$all') {
            if (Object.keys) {
                $que = Object.keys(jcQueue);
            } else {
                var key
                for (key in jcQueue) {
                    $que.push(key);
                }
            }
        } else {
            // TODO:重复值
            queues.forEach(function(q) {
                $que.push(jcQueue.hasOwnProperty(q) ? jcQueue[q] : jcQueue[q] = {})
            })

        }
        pb.fn.$que = $que;
        pb.fn.$channel = queues;

        return pb.fn
    }

    jc.mix(pb.fn = {}, Observable)
    pb.fn.$jcQueue = {}
    return pb
}